<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>4. 添加拖动和缩放 | 被删的前端游乐场</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="Just playing around">
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.1e2670bf.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.38d016d1.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.e3f029cb.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/98.c8e29b3c.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>Angular框架解读</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>玩转 Angular</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Cycle.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>D3.js 和 Tree</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-others/d3-tree/1-svg-and-d3.html" class="sidebar-link">1. 拜见 D3.js</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/2-init-a-d3-tree.html" class="sidebar-link">2. 简单的 Tree demo</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/3-ajax-for-node.html" class="sidebar-link">3. 动态请求子节点</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/4-zoom-amd-drag.html" aria-current="page" class="active sidebar-link">4. 添加拖动和缩放</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/d3-tree/4-zoom-amd-drag.html#d3-zoom" class="sidebar-link">d3-zoom</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/d3-tree/4-zoom-amd-drag.html#zoom-events" class="sidebar-link">Zoom Events</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/d3-tree/4-zoom-amd-drag.html#添加-zoom-事件的处理" class="sidebar-link">添加 zoom 事件的处理</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/d3-tree/4-zoom-amd-drag.html#根据节点数量和层级调整间距" class="sidebar-link">根据节点数量和层级调整间距</a></li></ul></li><li><a href="/front-end-playground/front-end-others/d3-tree/5-add-panel.html" class="sidebar-link">5. 添加浮层</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/6-add-smart-menu.html" class="sidebar-link">6. 添加右键菜单</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/7-text-path.html" class="sidebar-link">7. 曲线上的文字 textPath</a></li><li><a href="/front-end-playground/front-end-others/d3-tree/8-add-path-click.html" class="sidebar-link">8. 曲线 hover 和点击</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Three.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>BOX2D.js 文档与教程</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>因为业务需要折腾起了图表，该系列用于记录使用该库制作 Tree 图表的一些笔记。本节我们来给图表添加拖动和缩放吧。</p> <h1 id="添加鼠标事件"><a href="#添加鼠标事件" class="header-anchor">#</a> 添加鼠标事件</h1> <h2 id="d3-zoom"><a href="#d3-zoom" class="header-anchor">#</a> d3-zoom</h2> <p>不得不说，这节我们增加的拖动和缩放功能，都是通过<code>d3-zoom</code>模块来完成的。
<code>d3-zoom</code>可以对 selections 进行平移和缩放，它封装了浏览器支持的 input events 并对浏览器兼容性做了处理。</p> <p>我们先来介绍下基本的 API：</p> <p><strong>d3.zoom()</strong>
创建一个 zoom 操作。返回一个 zoom 对象方法，通常被传递给 selection.call 来调用。</p> <p><strong>zoom.scaleExtent([extent])</strong>
设置或获取缩放范围。默认为<code>[0, ∞]</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 这里我们创建了zomm操作，同时通过scaleExtent设置缩放区域为0.1-100倍。</span>
<span class="token keyword">var</span> zoom <span class="token operator">=</span> d3<span class="token punctuation">.</span><span class="token function">zoom</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">scaleExtent</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><strong>zoom.on(typenames[, listener])</strong>
三种情况：设置，取消，获取事件监听器。</p> <ol><li>如果指定了 listener，则为对应的 typenames 设置事件监听器。</li> <li>如果 listenter 为 null，则取消对应的 typenames 监听器。</li> <li>如果没有指定 listenter，则返回对应的 typenames 监听器。</li></ol> <p>typenames 是一个字符串，由 type 和 name 组成。也就是可以为同一种事件类型添加多个监听器。type 必须为如下几种：</p> <ul><li>start：开始缩放 (比如鼠标按下)</li> <li>zoom：开始缩放变换(比如拖拽)</li> <li>end：缩放结束(比如鼠标抬起 )</li></ul> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> zoom <span class="token operator">=</span> d3
  <span class="token punctuation">.</span><span class="token function">zoom</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token comment">// 设置缩放区域为0.1-100倍</span>
  <span class="token punctuation">.</span><span class="token function">scaleExtent</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token comment">// 监听缩放变换事件，包括拖动和滚轮</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 绑定zoom事件，通过单独定义dblclick.zoom，释放zoom双击事件（默认为双击放大，会与动态请求冲突）</span>
<span class="token function">selection</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>zoom<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;dblclick.zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>更多的 API 详情，请参考<a href="https://github.com/xswei/d3js_doc/tree/master/API/d3-zoom-master" target="_blank" rel="noopener noreferrer">d3-zoom<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。</p> <h2 id="zoom-events"><a href="#zoom-events" class="header-anchor">#</a> Zoom Events</h2> <p>当 zoom event listener 被调用时, d3.event 会被设置为当前的 zoom 事件。zoom event 对象由以下几部分组成:</p> <ul><li>target：当前的缩放 zoom behavior。</li> <li>type：事件类型:“start”, “zoom” 或者 “end”; 参考 zoom.on。</li> <li>transform：当前的 zoom transform(缩放变换)。</li> <li>sourceEvent：原始事件, 比如 mousemove 或 touchmove。</li></ul> <div class="language-js extra-class"><pre class="language-js"><code>zoom<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// 可以获取zoom事件当前的缩放状态</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>d3<span class="token punctuation">.</span>event<span class="token punctuation">.</span>transform<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="添加-zoom-事件的处理"><a href="#添加-zoom-事件的处理" class="header-anchor">#</a> 添加 zoom 事件的处理</h2> <p>svg 里面包括很多的子元素，我们这里采用给整个 svg 添加 zoom 事件，来进行完整的缩放和拖动处理：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 这里我们将svg元素，和子group元素拆分</span>
<span class="token keyword">var</span> svg <span class="token operator">=</span> d3
  <span class="token punctuation">.</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token string">&quot;body&quot;</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">&quot;svg&quot;</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span><span class="token string">&quot;width&quot;</span><span class="token punctuation">,</span> width <span class="token operator">+</span> margin<span class="token punctuation">.</span>right <span class="token operator">+</span> margin<span class="token punctuation">.</span>left<span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span><span class="token string">&quot;height&quot;</span><span class="token punctuation">,</span> height <span class="token operator">+</span> margin<span class="token punctuation">.</span>top <span class="token operator">+</span> margin<span class="token punctuation">.</span>bottom<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 子group元素存为view变量</span>
<span class="token keyword">var</span> view <span class="token operator">=</span> svg
  <span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">&quot;g&quot;</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span><span class="token string">&quot;transform&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;translate(&quot;</span> <span class="token operator">+</span> margin<span class="token punctuation">.</span>left <span class="token operator">+</span> <span class="token string">&quot;,&quot;</span> <span class="token operator">+</span> margin<span class="token punctuation">.</span>top <span class="token operator">+</span> <span class="token string">&quot;)&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 创建zoom操作</span>
<span class="token keyword">var</span> zoom <span class="token operator">=</span> d3
  <span class="token punctuation">.</span><span class="token function">zoom</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token comment">// 设置缩放区域为0.1-100倍</span>
  <span class="token punctuation">.</span><span class="token function">scaleExtent</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token comment">// 子group元素将响应zoom事件，并更新transform状态</span>
    view<span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span>
      <span class="token string">&quot;transform&quot;</span><span class="token punctuation">,</span>
      <span class="token string">&quot;translate(&quot;</span> <span class="token operator">+</span>
        <span class="token punctuation">(</span>d3<span class="token punctuation">.</span>event<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>x <span class="token operator">+</span> margin<span class="token punctuation">.</span>left<span class="token punctuation">)</span> <span class="token operator">+</span>
        <span class="token string">&quot;,&quot;</span> <span class="token operator">+</span>
        <span class="token punctuation">(</span>d3<span class="token punctuation">.</span>event<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>y <span class="token operator">+</span> margin<span class="token punctuation">.</span>top<span class="token punctuation">)</span> <span class="token operator">+</span>
        <span class="token string">&quot;) scale(&quot;</span> <span class="token operator">+</span>
        d3<span class="token punctuation">.</span>event<span class="token punctuation">.</span>transform<span class="token punctuation">.</span>k <span class="token operator">+</span>
        <span class="token string">&quot;)&quot;</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// svg层绑定zoom事件，同时释放zoom双击事件</span>
<span class="token function">svg</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>zoom<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;dblclick.zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>这里，不管是鼠标滚轮的事件还是拖动事件，都会触发 zoom 事件响应。如果说滚轮事件与页面上下滚动事件相斥的话，我们可以通过<code>zoom.filter()</code>来过滤。我们如果想要改成按下 ctrl 键的同时，滚动鼠标滚轮才进行缩放，可以这样修改：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> zoom <span class="token operator">=</span> d3
  <span class="token punctuation">.</span><span class="token function">zoom</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">scaleExtent</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">0.1</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// isWheelEvent为是否滚轮事件</span>
    <span class="token keyword">var</span> isWheelEvent <span class="token operator">=</span> d3<span class="token punctuation">.</span>event <span class="token keyword">instanceof</span> <span class="token class-name">WheelEvent</span><span class="token punctuation">;</span>
    <span class="token comment">// 返回是否ctrl与滚轮同时触发</span>
    <span class="token keyword">return</span> <span class="token operator">!</span>isWheelEvent <span class="token operator">||</span> <span class="token punctuation">(</span>isWheelEvent <span class="token operator">&amp;&amp;</span> d3<span class="token punctuation">.</span>event<span class="token punctuation">.</span>ctrlKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">&quot;zoom&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>效果如图，缩放前：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1513511660%281%29.png" alt="image"></p> <p>放大后：
<img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/1513511993%281%29.png" alt="image"></p> <h2 id="根据节点数量和层级调整间距"><a href="#根据节点数量和层级调整间距" class="header-anchor">#</a> 根据节点数量和层级调整间距</h2> <p>而当我们的层级树和子节点树上去之后，我们的节点会挤到一起，而要避免文字被遮挡，需要调整间距。</p> <p>我们先来定义两个函数方法，分别用来获取最深层数和最大子节点数。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 获取最多的子节点数</span>
<span class="token keyword">function</span> <span class="token function">getMax</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> max <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">.</span>children<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    max <span class="token operator">=</span> obj<span class="token punctuation">.</span>children<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
    obj<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">d</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> tmpMax <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMax</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>tmpMax <span class="token operator">&gt;</span> max<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        max <span class="token operator">=</span> tmpMax<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> max<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 获取最深层级数</span>
<span class="token keyword">function</span> <span class="token function">getDepth</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">var</span> depth <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">.</span>children<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    obj<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">d</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">var</span> tmpDepth <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getDepth</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>tmpDepth <span class="token operator">&gt;</span> depth<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        depth <span class="token operator">=</span> tmpDepth<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token number">1</span> <span class="token operator">+</span> depth<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>同时，我们在每次更新节点状态时，重新进行 tree 的大小调整：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">updateChart</span><span class="token punctuation">(</span><span class="token parameter">source</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 大致计算需要放大的倍数</span>
  <span class="token keyword">var</span> scale <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token function">getDepth</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">8</span> <span class="token operator">||</span> <span class="token number">0.5</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token function">getMax</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">12</span> <span class="token operator">||</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 定义Tree层级，并设置宽高</span>
  <span class="token keyword">var</span> treemap <span class="token operator">=</span> d3<span class="token punctuation">.</span><span class="token function">tree</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">[</span>height <span class="token operator">*</span> scale<span class="token punctuation">,</span> width<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 其他处理</span>
<span class="token punctuation">}</span>
</code></pre></div><h1 id="结束语"><a href="#结束语" class="header-anchor">#</a> 结束语</h1> <p>本节我们添加了鼠标操作，包括滚轮缩放和拖动，主要依靠 d3-zoom 模块来实现。同时，考虑文字重叠，也进行了些处理。<br>
细心的小伙伴们或许会发现 d3-drag 模块，骚年还没用到，不过或许区别在于整体的拖动和单个元素的拖动吧。<br> <a href="https://github.com/godbasin/godbasin.github.io/tree/blog-codes/d3-tree-notes/4-zoom-amd-drag" target="_blank" rel="noopener noreferrer">此处查看项目代码<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="http://d3.godbasin.com/4-zoom-amd-drag/index.html" target="_blank" rel="noopener noreferrer">此处查看页面效果<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-others/d3-tree/4-zoom-amd-drag.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-others/d3-tree/3-ajax-for-node.html" class="prev">
          3. 动态请求子节点
        </a></span> <span class="next"><a href="/front-end-playground/front-end-others/d3-tree/5-add-panel.html">
          5. 添加浮层
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-5412" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.1e2670bf.js" defer></script><script src="/front-end-playground/assets/js/2.38d016d1.js" defer></script><script src="/front-end-playground/assets/js/3.e3f029cb.js" defer></script><script src="/front-end-playground/assets/js/98.c8e29b3c.js" defer></script>
  </body>
</html>
